﻿using FPSO.HMI.Controls;
using SafeLoad.NControl;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;

namespace FPSO.HMI.Pipe
{
    class PipeGraph
    {
		//DEBUG 设备与管线相连
        public PipeGraph(Canvas canvas)
        {
            pumpList = new List<NPump>();
            valvesList = new List<UCValve>();
            pipeLineList = new List<PipeLineElement>();
            pipeThreeList = new List<ThreePointElement>();
            pipeFourList = new List<FourPointElement>();
            pumpPipeLineList = new List<PipeLineElement>();

            UIElementCollection eles = canvas.Children;
            foreach (UIElement e in eles)
            {
                if (e is NPipeLine line)
                {
                    pipeLineList.Add(new PipeLineElement(line));
                }
                else if (e is NPump pump)
                {
                    pumpList.Add(pump);
                }
                else if (e is NPipeLineThree three)
                {
                    pipeThreeList.Add(new ThreePointElement(three));
                }
                else if (e is NPipeLineFour four)
                {
                    pipeFourList.Add(new FourPointElement(four));
                }
                else if (e is UCValve valves)
                {
                    valvesList.Add(valves);
                }
            }

            //将阀门与管道关联
            foreach (UCValve v in valvesList)
            {
                //阀门的位置
                Point p = new Point(Canvas.GetLeft(v) + v.ActualWidth / 2, Canvas.GetTop(v) + v.ActualHeight / 2);

				PipeLineElement line = null;
                for (int i = 0; i < pipeLineList.Count; i++)
                {
                    //判断阀门是否在管道的范围内
                    if (pipeLineList[i].PointInLine(p) && pipeLineList[i].Valve == null)
                    {
                        line = pipeLineList[i];
                        //pipeLineList[i].Valves = v;
                        break;
                    }
                }
                if (line != null)
                {
                    line.Valve = v;
                }
                else
                {
                    //throw new Exception("没有找到与阀门关联的管道");
                }
            }

            //将泵与管道关联
            foreach (NPump pump in pumpList)
            {
                //泵的位置
                Point p = new Point(Canvas.GetLeft(pump) + pump.ActualWidth / 2, Canvas.GetTop(pump) + pump.ActualHeight / 2);
                PipeLineElement line = null;
                for (int i = 0; i < pipeLineList.Count; i++)
                {
                    if (pipeLineList[i].PointInLine(p) && pipeLineList[i].Valve == null)
                    {
                        line = pipeLineList[i];
                        break;
                    }
                }
                if (line != null)
                {
                    line.Pump = pump;
                    pumpPipeLineList.Add(line);
                }
                else
                {
                    List<PipeLineElement> lines = pipeLineList.Where(l => l.Port1Pos.X < 300 && l.Port1Pos.Y < 100).ToList();
                    throw new Exception("没有找到与泵关联的管道");
                }
            }

            //匹配三通管
            foreach (ThreePointElement three in pipeThreeList)
            {
                for (int i = 0; i < pipeLineList.Count; i++)
                {
                    three.Connect(pipeLineList[i]);
                }
            }

            //匹配四通管
            foreach (FourPointElement four in pipeFourList)
            {
                for (int i = 0; i < pipeLineList.Count; i++)
                {
                    four.Connect(pipeLineList[i]);
                }
            }

            //管道和管道匹配
            for (int i = 0; i < pipeLineList.Count; i++)
            {
                if (pipeLineList[i].Port1 == null || pipeLineList[i].Port2 == null)
                {
                    for (int j = i + 1; j < pipeLineList.Count; j++)
                    {
                        if (pipeLineList[j].Port1 == null || pipeLineList[j].Port2 == null)
                        {
                            pipeLineList[i].Connect(pipeLineList[j]);
                        }
                    }
                }
            }

            //检查管线图是否正常， 
            //1. 三通管每个通道都应该有连接
            foreach (ThreePointElement three in pipeThreeList)
            {
                if (three.Port1 == null || three.Port2 == null || three.Port3 == null)
                {
                    throw new Exception("三通管道初始化失败");
                }
            }

            //2. 四通管每个通道都应该有连接
            foreach (FourPointElement four in pipeFourList)
            {
                if (four.Port1 == null || four.Port2 == null || four.Port3 == null || four.Port4 == null)
                {
                    throw new Exception("四通管道初始化失败");
                }
            }

            //3. 管道最多有一段没有连接
            foreach (PipeLineElement line in pipeLineList)
            {
                if (line.Port1 == null && line.Port2 == null)
                {
                    throw new Exception("管道初始化失败");
                }
            }

        }

        private List<NPump> pumpList;
        private List<UCValve> valvesList;

        //private List<bool> pumpStateList;
        //private List<bool> valveStateList;

        private List<PipeLineElement> pipeLineList;
        private List<ThreePointElement> pipeThreeList;
        private List<FourPointElement> pipeFourList;

        private List<PipeLineElement> pumpPipeLineList;

        public void CalcPumpLines()
        {
            bool isChanged = false;
            foreach (NPump pump in pumpList)
            {
				string pumpname = pump.Name;
                if (pump.Tag == null || Convert.ToBoolean(pump.Tag) != pump.Active)
                {
                    isChanged = true;
                }

                pump.Tag = pump.Active;
            }
            foreach(UCValve valve in valvesList)
            {
				//if (valve.Tag != null && Convert.ToBoolean(valve.Tag) != valve.Active)
				if (valve.Tag != null && Convert.ToInt16(valve.Tag) != valve.ActiveStatus)
				{
					isChanged = true;
                }
				//valve.Tag = valve.Active;
				valve.Tag = valve.ActiveStatus;
            }

            //if (!isChanged)
            //{
            //    return;
            //}

            List<LinePath> inLines = new List<LinePath>();
            List<LinePath> outLines = new List<LinePath>();
            Stack<IPipeElement> stack = new Stack<IPipeElement>();

            ResetElementState();
            foreach (PipeLineElement pumpLine in pumpPipeLineList)
            {
                ResetElementFlag();
                if (pumpLine.Pump != null && pumpLine.Pump.Active)
                {
                    stack.Clear();
                    stack.Push(pumpLine);
                    IPipeElement inPort = null;
                    IPipeElement outPort = null;
                    //根据泵的方向和管道的方向确定泵的入口和出口
                    if (pumpLine.Port1IsPumpIn())
                    {
                        inPort = pumpLine.Port1;
                        outPort = pumpLine.Port2;
                    }
                    else
                    {
                        inPort = pumpLine.Port2;
                        outPort = pumpLine.Port1;
                    }

                    if (inPort != null)
                    {
                        stack.Push(inPort);
                        FindElement(stack, pumpLine, inLines);
                        stack.Pop();
                    }

                    if (outPort != null)
                    {
                        stack.Push(outPort);
                        FindElement(stack, pumpLine, outLines);
                        stack.Pop();
                    }

                    foreach (LinePath path in inLines)
                    {
                        for (int i = 0; i < path.Elements.Count; i++)
                        {
                            IPipeElement preEle = i > 0 ? path.Elements[i - 1] : null;
                            IPipeElement e = path.Elements[i];
                            IPipeElement nextEle = (i + 1) < path.Elements.Count ? path.Elements[i + 1] : null;
                            e.SetInPort(preEle);
                            e.SetOutPort(nextEle);
                        }
                    }
                    foreach (LinePath path in outLines)
                    {
                        for (int i = 0; i < path.Elements.Count; i++)
                        {
                            IPipeElement preEle = i > 0 ? path.Elements[i - 1] : null;
                            IPipeElement e = path.Elements[i];
                            IPipeElement nextEle = (i + 1) < path.Elements.Count ? path.Elements[i + 1] : null;
                            e.SetInPort(nextEle);
                            e.SetOutPort(preEle);
                        }
                    }
                }
            }

            UpdateElementUI();
        }

        private void FindElement(Stack<IPipeElement> stack, IPipeElement preElement, List<LinePath> pathList)
        {
            IPipeElement curEle = stack.Peek();
            if (!curEle.Flag)
            {
                curEle.Flag = true;
                if (curEle is PipeLineElement pipeline)
                {
                    if (pipeline.Pump != null)
                    {
                        //管道上有泵
                        return;
                    }

                    //if (pipeline.Valve != null && !pipeline.Valve.Active)
					if (pipeline.Valve != null && pipeline.Valve.ActiveStatus == 3)
					{
						//阀门关闭
						return;
                    }

                    if (pipeline.Port1 == null || pipeline.Port2 == null)
                    {
                        //已经结束
                        pathList.Add(new LinePath() { Elements = stack.ToList() });
                        return;
                    }

                    if (pipeline.Port1 == preElement)
                    {
                        stack.Push(pipeline.Port2);
                    }
                    else
                    {
                        stack.Push(pipeline.Port1);
                    }
                    FindElement(stack, curEle, pathList);
                    stack.Pop();
                }
                else if (curEle is ThreePointElement three)
                {
                    if (three.Port1 != preElement)
                    {
                        stack.Push(three.Port1);
                        FindElement(stack, curEle, pathList);
                        stack.Pop();
                    }
                    if (three.Port2 != preElement)
                    {
                        stack.Push(three.Port2);
                        FindElement(stack, curEle, pathList);
                        stack.Pop();
                    }
                    if (three.Port3 != preElement)
                    {
                        stack.Push(three.Port3);
                        FindElement(stack, curEle, pathList);
                        stack.Pop();
                    }
                }
                else if (curEle is FourPointElement four)
                {
                    if (four.Port1 != preElement)
                    {
                        stack.Push(four.Port1);
                        FindElement(stack, curEle, pathList);
                        stack.Pop();
                    }
                    if (four.Port2 != preElement)
                    {
                        stack.Push(four.Port2);
                        FindElement(stack, curEle, pathList);
                        stack.Pop();
                    }
                    if (four.Port3 != preElement)
                    {
                        stack.Push(four.Port3);
                        FindElement(stack, curEle, pathList);
                        stack.Pop();
                    }
                    if (four.Port4 != preElement)
                    {
                        stack.Push(four.Port4);
                        FindElement(stack, curEle, pathList);
                        stack.Pop();
                    }
                }
            }
        }

        private void ResetElementState()
        {
            foreach (PipeLineElement line in pipeLineList)
            {
                line.Reset();
            }

            foreach (ThreePointElement three in pipeThreeList)
            {
                three.Reset();
            }

            foreach (FourPointElement four in pipeFourList)
            {
                four.Reset();
            }
        }

        private void ResetElementFlag()
        {
            foreach (PipeLineElement line in pipeLineList)
            {
                line.ResetFlag();
            }

            foreach (ThreePointElement three in pipeThreeList)
            {
                three.ResetFlag();
            }

            foreach (FourPointElement four in pipeFourList)
            {
                four.ResetFlag();
            }
        }

        private void UpdateElementUI()
        {
            foreach (PipeLineElement line in pipeLineList)
            {
                line.UpdateUI();
            }

            foreach (ThreePointElement three in pipeThreeList)
            {
                three.UpdateUI();
            }

            foreach (FourPointElement four in pipeFourList)
            {
                four.UpdateUI();
            }
        }

        private class LinePath
        {
            public LinePath()
            {
                Elements = new List<IPipeElement>();
            }

            public List<IPipeElement> Elements { get; set; }
        }

    }
}
